#include "Algorithms.h"


inline void
PrintTask::applyOn(VirtualInstruction& instruction, WorkList& continuations) {  
    assert(dynamic_cast<const PrintAgenda*>(&continuations));
    PrintAgenda& agenda = (PrintAgenda&) continuations;
    agenda.m_out << instruction.getRegistrationIndex() << "  ";
    if (instruction.getRegistrationIndex() < 10)
        agenda.m_out << ' ';
    for (int shift = m_ident; --shift >= 0;)
        agenda.m_out << "  ";
    instruction.print(agenda.m_out);
}

bool
PhiInsertionTask::IsBefore::operator()(VirtualExpression* first, VirtualExpression* second) const{
    if (first->type() == second->type())
    {
        if (first->type() == VirtualExpression::TLocalVariable)
        {
            assert(dynamic_cast<const LocalVariableExpression*>(first)
                   && dynamic_cast<const LocalVariableExpression*>(second));
            return ((const LocalVariableExpression&) *first).getGlobalIndex()
                    < ((const LocalVariableExpression&) *second).getGlobalIndex();
        }

        if (first->type() == VirtualExpression::TParameter)
        {
            assert(dynamic_cast<const ParameterExpression*>(first)
                   && dynamic_cast<const ParameterExpression*>(second));
            return ((const ParameterExpression&) *first).getIndex()
                    < ((const ParameterExpression&) *second).getIndex();
        }

        assert(dynamic_cast<const GlobalVariableExpression*>(first)
               && dynamic_cast<const GlobalVariableExpression*>(second));
        return ((const GlobalVariableExpression&) *first).getIndex()
                < ((const GlobalVariableExpression&) *second).getIndex();
    }

    return first->type() > second->type();
}


void
LabelPhiFrontierAgenda::propagate(const LabelInstruction& label) {
    assert(label.mark);
    LabelResult& result = *(LabelResult*) label.mark;

    for (std::vector<GotoInstruction*>::const_iterator frontierIter = label.getDominationFrontier().begin();
         frontierIter != label.getDominationFrontier().end(); ++frontierIter)
    {
        std::set<VirtualExpression*, IsBefore> modified;
        LabelResult& receiver = *(LabelResult*) (*frontierIter)->getSNextInstruction()->mark;

        for (LabelResult::iterator exprIter = result.map().begin(); exprIter != result.map().end(); ++exprIter)
        {
            LocalVariableExpression afterScope = receiver.getAfterScopeLocalVariable();
            if (IsBefore().operator()(exprIter->first, &afterScope))
            {
                LabelResult::iterator found = receiver.map().find(exprIter->first);
                if (found == receiver.map().end())
                {
                    std::pair<VirtualExpression*, std::pair<GotoInstruction*, GotoInstruction*> > insert;
                    insert.first = exprIter->first;
                    insert.second.first = *frontierIter;
                    insert.second.second = NULL;
                    found = receiver.map().insert(found, insert);

                    if (modified.find(exprIter->first) == modified.end())
                        modified.insert(exprIter->first);
                }
                else if ((found->second.first != *frontierIter) && (found->second.second != *frontierIter))
                {
                    if (found->second.first == NULL)
                        found->second.first = *frontierIter;
                    else if (found->second.second == NULL)
                        found->second.second = *frontierIter;
                    else
                    { assert(false); }
                };
            };
        };

        if (!modified.empty())
            addNewAsFirst(new LabelPhiFrontierTask(
                              *(LabelInstruction*) (*frontierIter)->getSNextInstruction(), modified));
    };
}


void
LabelPhiFrontierAgenda::propagateOn(const LabelInstruction& label,
                                    const std::set<VirtualExpression*, IsBefore>& originModified) {
    for (std::vector<GotoInstruction*>::const_iterator frontierIter = label.getDominationFrontier().begin();
         frontierIter != label.getDominationFrontier().end(); ++frontierIter)
    {
        std::set<VirtualExpression*, IsBefore> modified;
        LabelResult& receiver = *(LabelResult*) (*frontierIter)->getSNextInstruction()->mark;
        for (std::set<VirtualExpression*, IsBefore>::iterator exprIter = originModified.begin();
             exprIter != originModified.end(); ++exprIter)
        {
            LocalVariableExpression afterScope = receiver.getAfterScopeLocalVariable();
            if (IsBefore().operator()(*exprIter, &afterScope))
            {
                LabelResult::iterator found = receiver.map().find(*exprIter);
                if (found == receiver.map().end())
                {
                    std::pair<VirtualExpression*, std::pair<GotoInstruction*, GotoInstruction*> > insert;
                    insert.first = *exprIter;
                    insert.second.first = *frontierIter;
                    insert.second.second = NULL;
                    found = receiver.map().insert(found, insert);

                    if (modified.find(*exprIter) == modified.end())
                        modified.insert(*exprIter);
                }
                else if ((found->second.first != *frontierIter) && (found->second.second != *frontierIter))
                {
                    if (found->second.first == NULL)
                        found->second.first = *frontierIter;
                    else if (found->second.second == NULL)
                        found->second.second = *frontierIter;
                    else
                    { assert(false); }
                };
            };
        };

        if (!modified.empty())
            addNewAsFirst(new LabelPhiFrontierTask(*(LabelInstruction*)
                                                   (*frontierIter)->getSNextInstruction(), modified));
    };
}


Comparison
RenamingTask::VariableRenaming::compare(const VariableRenaming& source) const {
    assert(m_function == source.m_function);
    if (m_toReplace->type() == source.m_toReplace->type())
    {
        if (m_toReplace->type() == VirtualExpression::TLocalVariable)
        {
            assert(dynamic_cast<const LocalVariableExpression*>(m_toReplace)
                   && dynamic_cast<const LocalVariableExpression*>(source.m_toReplace));
            int thisIndex = ((const LocalVariableExpression&) *m_toReplace).getFunctionIndex(*m_function),
                    sourceIndex = ((const LocalVariableExpression&) *source.m_toReplace).getFunctionIndex(*m_function);

            return (thisIndex < sourceIndex) ? CLess : ((thisIndex > sourceIndex) ? CGreater : CEqual);
        };

        if (m_toReplace->type() == VirtualExpression::TParameter)
        {
            assert(dynamic_cast<const ParameterExpression*>(m_toReplace)
                   && dynamic_cast<const ParameterExpression*>(source.m_toReplace));
            int thisIndex = ((const ParameterExpression&) *m_toReplace).getIndex(),
                    sourceIndex = ((const ParameterExpression&) *source.m_toReplace).getIndex();

            return (thisIndex < sourceIndex) ? CLess : ((thisIndex > sourceIndex) ? CGreater : CEqual);
        };

        assert(dynamic_cast<const GlobalVariableExpression*>(m_toReplace)
               && dynamic_cast<const GlobalVariableExpression*>(source.m_toReplace));
        int thisIndex = ((const GlobalVariableExpression&) *m_toReplace).getIndex(),
                sourceIndex = ((const GlobalVariableExpression&) *source.m_toReplace).getIndex();

        return (thisIndex < sourceIndex) ? CLess : ((thisIndex > sourceIndex) ? CGreater : CEqual);
    };

    return (m_toReplace->type() < source.m_toReplace->type()) ? CGreater : CLess;
}


bool
RenamingTask::VariableRenaming::setDominator(VirtualInstruction& dominator,GotoInstruction* previousLabel) {
    assert(m_lastDominator || !m_parent.get());
    if (m_lastDominator && m_lastDominator->getDominationHeight() >= dominator.getDominationHeight())
    {
        if (m_newValue && m_lastDominator != previousLabel)
        {
            delete m_newValue;
            m_newValue = NULL;
        };

        m_lastDominator = &dominator;

        while (m_parent.get() && m_parent->m_lastDominator
               && m_parent->m_lastDominator->getDominationHeight() >= dominator.getDominationHeight())
            m_parent = m_parent->m_parent;
    }
    else if (m_newValue)
    {
        std::shared_ptr<VariableRenaming> newParent(new VariableRenaming(*this, Transfert()));
        newParent->m_parent = m_parent;
        m_parent = newParent;
    };

    m_lastDominator = &dominator;

    return m_newValue || m_parent.get();
}




